﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Nop.Core.Configuration;
using Nop.Core.Infrastructure.DependencyManagement;

namespace Nop.Core.Infrastructure
{
    /// <summary>
    /// Engine
    /// NOP的引擎   相当于程序的内核
    /// 引擎负责了对应用程序实例的管理 ，NOP的引擎基本思想是为了实现对应用程序在生命周期内
    /// 进行已经被创建的实例的管理或者对创建的定时任务调度进行管理
    /// 1  instance manage
    /// 2  manage all ScheduleTasks 
    /// </summary>
    public class NopEngine : IEngine
    {
        #region Fields
        /// <summary>
        /// NOP中使用了AutoFac作为IOC依赖容器  此容器被封装在ContainerManager中
        /// 所有 毫无疑问  内核必然经常要与实例池  Instance Pool 中的实例进行交互
        /// </summary>
        private ContainerManager _containerManager;

        #endregion

        #region Utilities

        /// <summary>
        /// Run startup tasks
        /// 执行任务调度
        /// </summary>
        protected virtual void RunStartupTasks()
        {
            var typeFinder = _containerManager.Resolve<ITypeFinder>();
            var startUpTaskTypes = typeFinder.FindClassesOfType<IStartupTask>();
            var startUpTasks = new List<IStartupTask>();
            foreach (var startUpTaskType in startUpTaskTypes)
                startUpTasks.Add((IStartupTask)Activator.CreateInstance(startUpTaskType));
            //sort
            startUpTasks = startUpTasks.AsQueryable().OrderBy(st => st.Order).ToList();
            foreach (var startUpTask in startUpTasks)
                startUpTask.Execute();
        }

        /// <summary>
        /// Register dependencies
        /// 基于内核  引擎 创建IOC容器池
        /// </summary>
        /// <param name="config">Config</param>
        protected virtual void RegisterDependencies(NopConfig config)
        {
            ///创建IOC容器
            var builder = new ContainerBuilder();
            var container = builder.Build();

            //we create new instance of ContainerBuilder
            //because Build() or Update() method can only be called once on a ContainerBuilder.
            //注意：AutoFac中的ContainerBuilder上述两个方法只能被这个类型的实例调用一次，也就是要么Build 要么Update，！

            //dependencies
            var typeFinder = new WebAppTypeFinder(config);
            builder = new ContainerBuilder();///所以 再次构建一个容器构建辅助类  来实现Update一个容器的操作
            builder.RegisterInstance(config).As<NopConfig>().SingleInstance();
            builder.RegisterInstance(this).As<IEngine>().SingleInstance();
            builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
            builder.Update(container);

            //register dependencies provided by other assemblies
            builder = new ContainerBuilder();
            ///对程序集中  所有实现此接口IDependencyRegistrar的类 进行依赖实例的注册。。。。。。。。。。。。
            var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
            var drInstances = new List<IDependencyRegistrar>();
            foreach (var drType in drTypes)
                drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
            //sort
            drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
            foreach (var dependencyRegistrar in drInstances)
                dependencyRegistrar.Register(builder, typeFinder);
            ///注册实例后 更新容器对象  将实例管理 映射到容器中
            builder.Update(container);


            this._containerManager = new ContainerManager(container);
            
            //set dependency resolver----重要：实现ASP.NET MVC的依赖注入 自3.3版本后  NOP团队移除了自己开发的
            //实例管理工具NopDependencyResolver 转而使用Autofac内置的实例化工具
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }

        #endregion

        #region Methods
        
        /// <summary>
        /// Initialize components and plugins in the nop environment.
        /// 当进行引擎初始化工作的时候  基于配置文件 对引擎进行依赖注入实例
        /// </summary>
        /// <param name="config">Config</param>
        public void Initialize(NopConfig config)
        {
            //register dependencies  进行实例的依赖注册
            RegisterDependencies(config);

            //startup tasks 是否忽略执行任务
            if (!config.IgnoreStartupTasks)
            {
                RunStartupTasks();
            }

        }

        /// <summary>
        /// Resolve dependency
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <returns></returns>
        public T Resolve<T>() where T : class
		{
            return ContainerManager.Resolve<T>();
		}

        /// <summary>
        ///  Resolve dependency
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        public object Resolve(Type type)
        {
            return ContainerManager.Resolve(type);
        }
        
        /// <summary>
        /// Resolve dependencies
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <returns></returns>
        public T[] ResolveAll<T>()
        {
            return ContainerManager.ResolveAll<T>();
        }

		#endregion

        #region Properties

        /// <summary>
        /// Container manager
        /// </summary>
        public ContainerManager ContainerManager
        {
            get { return _containerManager; }
        }

        #endregion
    }
}
